<template>
  <div
    class="player"
    v-show="playList.length"
  >
    <transition
      name="normal"
      @enter="enter"
      @after-enter="afterEnter"
      @after-leave="afterLeave"
      @leave="leave"
    >
      <div
        class="normal-player"
        v-show="fullScreen"
      >
        <div class="background">
          <img :src="currentSong?.pic">
        </div>
        <div class="top">
          <div
            class="back"
            @click="goBack"
          >
            <i class="icon-back"></i>
          </div>
          <h1 class="title">{{currentSong.name}}</h1>
          <h2 class="subtitle">{{currentSong.singer}}</h2>
        </div>
        <div
          class="middle"
          @touchstart.prevent="onMiddleTouchStart"
          @touchmove.prevent="onMiddleTouchMove"
          @touchend.prevent="onMiddleTouchEnd"
        >
          <div
            class="middle-l"
            :style="middleLStyle"
          >
            <div
              ref="cdWrapperRef"
              class="cd-wrapper"
            >
              <div
                class="cd"
              >
                <img
                  class="image"
                  :class="cdCls"
                  :src="currentSong.pic">
              </div>
            </div>
            <div class="playing-lyric-wrapper">
              <div class="playing-lyric">{{playingLyric}}</div>
            </div>
          </div>
          <Scroll
            class="middle-r"
            ref="lyricScrollRef"
            :style="middleRStyle"
          >
            <div class="lyric-wrapper">
              <div v-if="currentLyric" ref="lyricListRef">
                <p
                  class="text"
                  :class="{'current': currentLineNum ===index}"
                  v-for="(line,index) in currentLyric.lines"
                  :key="line.num"
                >
                  {{line.txt}}
                </p>
              </div>
              <div class="pure-music" v-show="pureMusicLyric">
                <p>{{pureMusicLyric}}</p>
              </div>
            </div>
          </Scroll>
        </div>
        <div class="bottom">
          <div class="dot-wrapper">
            <span class="dot" :class="{'active':currentShow==='cd'}"></span>
            <span class="dot" :class="{'active':currentShow==='lyric'}"></span>
          </div>
          <div class="progress-wrapper">
            <span class="time time-l">{{formatTime(currentTime)}}</span>
            <div class="progress-bar-wrapper">
              <ProgressBar
                ref="barRef"
                :progress="progress"
                @progress-changing="onProgressChanging"
                @progress-changed="onProgressChanged"
              ></ProgressBar>
            </div>
            <span class="time time-r">{{formatTime(currentSong.duration)}}</span>
          </div>
          <div class="operators">
            <div class="icon i-left">
              <i @click="changeMode" :class="modeIcon"></i>
            </div>
            <div class="icon i-left" :class="disableCls">
              <i @click="prev" class="icon-prev"></i>
            </div>
            <div class="icon i-center" :class="disableCls">
              <i @click="togglePlay" :class="playIcon"></i>
            </div>
            <div class="icon i-right" :class="disableCls">
              <i @click="next" class="icon-next"></i>
            </div>
            <div class="icon i-right">
              <i @click="toggleFavorite(currentSong)" :class="getFavoriteIcon(currentSong)"></i>
            </div>
          </div>
        </div>
      </div>
    </transition>
    <mini-player
      :progress="progress"
      :togglePlay="togglePlay"
    ></mini-player>
    <audio ref="audioRef"
           @pause="onpause"
           @canplay="onReady"
           @timeupdate="ontimeupdate"
           @ended="onended"
           @erroe="onerror"
    ></audio>
  </div>
</template>

<script>
import { useStore } from 'vuex'
import { computed, watch, ref, nextTick, provide } from 'vue'
import Scroll from '../base/scroll/Scroll'
import ProgressBar from './ProgressBar'
import MiniPlayer from './MiniPlayer'
import useModeEffect from './use-mode'
import useFavoriteEffect from './use-favorite'
import useCdEffect from './use-cd'
import useLyricEffect from './use-lyric'
import { formatTime } from '../../assets/js/util'
import useMiddleInteractiveEffect from './use-middle-interactive'
import useAnimationEffect from './use-animation'
import useAudioEffect from './use-audio'

// 图标状态相关
const useIconStateEffect = (songReady) => {
  const store = useStore()
  const playing = computed(() => store.state.playing)
  const playIcon = computed(() => {
    return playing.value ? 'icon-pause' : 'icon-play'
  })
  const disableCls = computed(() => {
    return songReady.value ? '' : 'disable'
  })
  return { playIcon, disableCls }
}

// 播放状态
const useAudioStateEffect = (songReady, currentTime, audioRef, playLyric, stopLyric) => {
  const store = useStore()
  const currentSong = computed(() => store.getters.currentSong)
  const playing = computed(() => store.state.playing)
  // 窃听当前歌曲变化
  watch(currentSong, (newSong) => {
    if (!newSong.id || !newSong.url) return
    currentTime.value = 0 // 切换歌曲currentTime置为初值
    songReady.value = false // 切换歌曲songRead置为初值
    const audioEl = audioRef.value
    audioEl.src = newSong.url
    audioEl.play()
    store.commit('setPlayingState', true)
  })
  // 窃听当前播放状态
  watch(playing, (newPlaying) => {
    if (!songReady.value) return // audio音频是否准备完成
    const audioEl = audioRef.value
    if (newPlaying) {
      audioEl.play()
      playLyric()
    } else {
      audioEl.pause()
      stopLyric()
    }
  })
  return { currentSong }
}

// 显示隐藏播放器
const useShowHideEffect = (progress) => {
  const store = useStore()
  const barRef = ref(null)
  const fullScreen = computed(() => store.state.fullScreen)
  const goBack = () => {
    store.commit('setFullScreen', false)
  }
  // 窃听播放器显示隐藏
  watch(fullScreen, async (newFullScreen) => {
    if (newFullScreen) {
      await nextTick()
      barRef.value.setOffset(progress.value)
    }
  })
  return { barRef, fullScreen, goBack }
}

// 进度条相关
const useProgressEffect = (currentTime, playLyric, stopLyric, audioRef) => {
  const store = useStore()
  const progressChanging = ref(false)
  const playing = computed(() => store.state.playing)
  const currentSong = computed(() => store.getters.currentSong)
  // 窃听进度条正在拖动
  const onProgressChanging = (progress) => {
    progressChanging.value = true
    currentTime.value = currentSong.value.duration * progress
    playLyric()
    stopLyric()
  }
  // 窃听进度条拖动完成
  const onProgressChanged = (progress) => {
    progressChanging.value = false
    audioRef.value.currentTime = currentTime.value = currentSong.value.duration * progress
    playLyric()
    if (!playing.value) {
      store.commit('setPlayingState', true)
    }
  }
  const progress = computed(() => {
    return currentTime.value / currentSong.value.duration
  })
  provide('progress', progress)
  return { onProgressChanging, onProgressChanged, progress, progressChanging, currentTime }
}

export default {
  name: 'Player',
  setup () {
    const songReady = ref(false)
    const currentTime = ref(0)
    const audioRef = ref(null)

    // hook
    // 播放模式相关
    const { modeIcon, changeMode } = useModeEffect()

    // 歌曲喜欢相关
    const { getFavoriteIcon, toggleFavorite } = useFavoriteEffect()

    // cd相关
    const { cdCls } = useCdEffect()

    // 歌词相关
    const {
      currentLyric, currentLineNum, playLyric,
      lyricScrollRef, lyricListRef, stopLyric,
      pureMusicLyric, playingLyric
    } = useLyricEffect(songReady, currentTime)

    // cd和歌词切换
    const {
      currentShow, middleLStyle, middleRStyle,
      onMiddleTouchStart, onMiddleTouchMove, onMiddleTouchEnd
    } = useMiddleInteractiveEffect()

    // 播放状态
    const { currentSong } = useAudioStateEffect(songReady, currentTime, audioRef, playLyric, stopLyric)

    // 进度条相关
    const {
      onProgressChanging, onProgressChanged, progress,
      progressChanging
    } = useProgressEffect(currentTime, playLyric, stopLyric, audioRef)

    // audio播放歌曲相关
    const {
      ontimeupdate, onpause, onerror, onReady, onended,
      prev, next, togglePlay, playList
    } = useAudioEffect(songReady, currentTime, progressChanging, playLyric, audioRef)

    // 显示隐藏播放器
    const { barRef, fullScreen, goBack } = useShowHideEffect(progress)

    // 动画相关
    const {
      cdWrapperRef, enter, afterEnter,
      leave, afterLeave
    } = useAnimationEffect()

    // 图标状态相关
    const { playIcon, disableCls } = useIconStateEffect(songReady)

    return {
      fullScreen,
      currentSong,
      barRef,
      currentTime,
      audioRef,
      playList,
      goBack,
      playIcon,
      progress,
      disableCls,
      formatTime,
      ontimeupdate,
      onpause,
      onReady,
      onerror,
      onended,
      onProgressChanging,
      onProgressChanged,
      prev,
      togglePlay,
      next,
      modeIcon,
      changeMode,
      getFavoriteIcon,
      toggleFavorite,
      cdCls,
      currentLyric,
      currentLineNum,
      lyricScrollRef,
      lyricListRef,
      pureMusicLyric,
      playingLyric,
      currentShow,
      middleLStyle,
      middleRStyle,
      onMiddleTouchStart,
      onMiddleTouchMove,
      onMiddleTouchEnd,
      cdWrapperRef,
      enter,
      afterEnter,
      leave,
      afterLeave
    }
  },
  components: {
    ProgressBar, Scroll, MiniPlayer
  }
}
</script>

<style lang="scss" scoped>
  .player {
    .normal-player {
      position: fixed;
      left: 0;
      right: 0;
      top: 0;
      bottom: 0;
      z-index: 150;
      background: $color-background;

      .background {
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        z-index: -1;
        opacity: 0.6;
        filter: blur(20px);

        img {
          width: 100%;
          height: 100%;
        }
      }

      .top {
        position: relative;
        margin-bottom: 25px;

        .back {
          position: absolute;
          top: 0;
          left: 6px;
          z-index: 50;
        }

        .icon-back {
          display: block;
          padding: 9px;
          font-size: $font-size-large-x;
          color: $color-theme;
          transform: rotate(-90deg);
        }

        .title {
          width: 70%;
          margin: 0 auto;
          line-height: 40px;
          text-align: center;
          @include no-wrap();
          font-size: $font-size-large;
          color: $color-text;
        }

        .subtitle {
          line-height: 20px;
          text-align: center;
          font-size: $font-size-medium;
          color: $color-text;
        }
      }

      .middle {
        position: fixed;
        width: 100%;
        top: 80px;
        bottom: 170px;
        white-space: nowrap;
        font-size: 0;

        .middle-l {
          display: inline-block;
          vertical-align: top;
          position: relative;
          width: 100%;
          height: 0;
          padding-top: 80%;

          .cd-wrapper {
            position: absolute;
            left: 10%;
            top: 0;
            width: 80%;
            box-sizing: border-box;
            height: 100%;

            .cd {
              width: 100%;
              height: 100%;
              border-radius: 50%;

              img {
                position: absolute;
                left: 0;
                top: 0;
                width: 100%;
                height: 100%;
                box-sizing: border-box;
                border-radius: 50%;
                border: 10px solid rgba(255, 255, 255, 0.1);
                animation: rotate 20s linear infinite
              }

              .paused {
                animation-play-state: paused;
              }

              .running {
                animation-play-state: running;
              }
            }
          }

          .playing-lyric-wrapper {
            width: 80%;
            margin: 30px auto 0 auto;
            overflow: hidden;
            text-align: center;

            .playing-lyric {
              height: 20px;
              line-height: 20px;
              font-size: $font-size-medium;
              color: $color-text-l;
            }
          }
        }

        .middle-r {
          display: inline-block;
          vertical-align: top;
          width: 100%;
          height: 100%;
          overflow: hidden;

          .lyric-wrapper {
            width: 80%;
            margin: 0 auto;
            overflow: hidden;
            text-align: center;

            .text {
              line-height: 32px;
              color: $color-text-l;
              font-size: $font-size-medium;

              &.current {
                color: $color-text;
              }
            }

            .pure-music {
              padding-top: 50%;
              line-height: 32px;
              color: $color-text-l;
              font-size: $font-size-medium;
            }
          }
        }
      }

      .bottom {
        position: absolute;
        bottom: 50px;
        width: 100%;

        .dot-wrapper {
          text-align: center;
          font-size: 0;

          .dot {
            display: inline-block;
            vertical-align: middle;
            margin: 0 4px;
            width: 8px;
            height: 8px;
            border-radius: 50%;
            background: $color-text-l;

            &.active {
              width: 20px;
              border-radius: 5px;
              background: $color-text-ll;
            }
          }
        }

        .progress-wrapper {
          display: flex;
          align-items: center;
          width: 80%;
          margin: 0px auto;
          padding: 10px 0;

          .time {
            color: $color-text;
            font-size: $font-size-small;
            flex: 0 0 40px;
            line-height: 30px;
            width: 40px;

            &.time-l {
              text-align: left;
            }

            &.time-r {
              text-align: right;
            }
          }

          .progress-bar-wrapper {
            flex: 1;
          }
        }

        .operators {
          display: flex;
          align-items: center;

          .icon {
            flex: 1;
            color: $color-theme;

            &.disable {
              color: $color-theme-d;
            }

            i {
              font-size: 30px;
            }
          }

          .i-left {
            text-align: right;
          }

          .i-center {
            padding: 0 20px;
            text-align: center;

            i {
              font-size: 40px;
            }
          }

          .i-right {
            text-align: left
          }

          .icon-favorite {
            color: $color-sub-theme;
          }
        }
      }

      &.normal-enter-active, &.normal-leave-active {
        transition: all .6s;

        .top, .bottom {
          transition: all .6s cubic-bezier(0.45, 0, 0.55, 1);
        }
      }

      &.normal-enter-from, &.normal-leave-to {
        opacity: 0;

        .top {
          transform: translate3d(0, -100px, 0);
        }

        .bottom {
          transform: translate3d(0, 100px, 0)
        }
      }
    }
  }
</style>
